"""
Bitvector based on numpy. Slices will operate with numpy slices only.

Adapted from a posting by Josiah Carlson on the pyrex list:

http://osdir.com/ml/python.pyrex/2005-10/msg00073.html

>>> b = BitVector( size=10 )
>>> b[:] 
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
>>> b[9] = 0
>>> b[:] 
[1, 1, 1, 1, 1, 1, 1, 1, 1, 0]
>>> b[3:7] = numpy.zeros(4, numpy.int16 )
>>> b[:]
[1, 1, 1, 0, 0, 0, 0, 1, 1, 0]

$Rev: 56 $ 
$Author: ialbert $ 
$Date: 2008-01-01 07:33:58 -0500 (Tue, 01 Jan 2008) $
"""
import numpy

ONE  = numpy.int16(1)
ZERO = numpy.int16(0)

class BitVector:
    def __init__(self, size, default=True ):
        "Initialize the bitvector"
        self.size = size
        actual_size = ( size+15 ) // 16
        if default:
            self.vector = numpy.ones( actual_size, numpy.int16 ) * 65535
        else:
            self.vector = numpy.zeros( actual_size, numpy.int16 )

    def set_bit(self, posn, val):
        "Sets the value of a bit"
        val = val and ONE or ZERO
        block = posn//16
        shift = posn&15
        cv = self.vector[block]
        if (cv>>shift)&ONE != val:
            if val:
                self.vector[block] = cv | (ONE << shift)
            else:
                self.vector[block] = cv ^ (ONE << shift)
        
    def get_bit(self, posn):
        "Returns the value of a bit"
        return (self.vector[posn//16]>>(posn&15)) & ONE

    __getitem__ = get_bit                                       
    __setitem__ = set_bit 
   
    def __setslice__(self, i, j, sequence):
        for index, value in enumerate( sequence):
            self[index+i] = value
    
    def __getslice__(self, i, j ):
        j = min(self.size, j)
        return map( self.get_bit, xrange(i, j) )
    
def test(verbose=0):
    """
    Main testrunnner
    """
    import doctest
    doctest.testmod( optionflags=doctest.ELLIPSIS + doctest.NORMALIZE_WHITESPACE, verbose=verbose )

if __name__ == '__main__':
    test(verbose=0)
    
    BIG = 3*10**8

    b = BitVector( size=BIG )
    #time.sleep(5)

